#include <deque>
#include <vector>
#include <string>
#include <cstring>
#include <fstream>
#include <iostream>
#include <algorithm>

#include "syn.hpp"

using namespace std;

static void split_with_str(const string &str, const string &sep, vector<string> &res) {
	res.clear();
	string::size_type pos1 = 0, pos2 = str.find(sep);
	while (pos2 != string::npos) {
		res.push_back(str.substr(pos1, pos2 - pos1));

		pos1 = pos2 + sep.size();
		pos2 = str.find(sep, pos1);
	}

	if (pos1 != str.length())
		res.push_back(str.substr(pos1));
}

static void split_with_char(const char *str, const char *sep, vector<string> &res) {
	res.clear();
	char *tmp;
	char buff[150];
	strncpy(buff, str, 150);
	tmp = strtok(buff, sep);
	while (tmp != nullptr) {
		res.push_back(string(tmp));
		tmp = strtok(nullptr, sep);
	}
}

void insert_into_vector(vector<string> &vec, string &str) {
	if (find(vec.begin(), vec.end(), str) != vec.end()) {
		return;
	}
	vec.push_back(str);
}

void Syn::read_rules(const char *grammar) {
	ifstream infile(grammar);

	bool flag = true;
	int len = 150;
	char buff[150];
	string sep = " -> ";

	while (!infile.eof()) {
		produce.push_back(pair<string, vector<string>>());

		infile.getline(buff, len);
		vector<string> prod;
		split_with_str(buff, sep, prod);
		produce.back().first = string(prod[0]);
		VN.insert(prod[0]);
		insert_into_vector(symbols, prod[0]);

		if (flag) {
			start = prod[0];
			flag = false;
		}

		vector<string> res;
		split_with_char(prod[1].c_str(), " ", res);
		for (int cnt = 0; cnt < res.size(); ++cnt) {
			produce.back().second.push_back(string(res[cnt]));
			insert_into_vector(symbols, res[cnt]);
		}
	}

	for (auto iter = symbols.begin(); iter != symbols.end(); ++iter) {
		if (VN.find(*iter) == VN.end()) {
			VT.insert(*iter);
		}
	}

	infile.close();
}

void Syn::expand() {
	string new_start = start+"\'";
	auto new_produce = pair<string, vector<string>>(new_start, vector<string>());
	new_produce.second.push_back(start);

	VN.insert(new_start);
	symbols.insert(symbols.begin(), new_start);
	produce.insert(produce.begin(), new_produce);
	start = new_start;
}

void Syn::print_self() {
	int cnt = 0;
	cout << "[start]: " << endl << start << endl << endl;

	cout << "[VT]:" << endl;
	for (auto iter = VT.begin(); iter != VT.end(); ++iter) {
		cout << *iter << " ";
		if ((cnt++ % 5) == 0) 
			cout << endl;
	}
	cout << endl << endl;

	cout << "[VN]:" << endl;
	for (auto iter = VN.begin(); iter != VN.end(); ++iter) {
		cout << *iter << " ";
		if ((cnt++ % 5) == 0) 
			cout << endl;
	}
	cout << endl << endl;

	cout << "[produce]: " << produce.size() << endl;
	for (int i = 0; i < produce.size(); ++i) {
		cout << produce[i].first << " -> ";
		for (int j = 0; j < produce[i].second.size(); ++j) {
			cout << "\""<< produce[i].second[j] << "\" ";
		}
		cout << endl;
	}
	cout << endl;
}
